package com.hksj.common.core.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.hksj.common.core.excelhandler.ExportExcelHandler;
import org.apache.poi.ss.usermodel.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

public class EasyExcelUtil {
    /**
     * 导出表格
     */
    public static void export(HttpServletResponse response, List<?> dataList, String templateFilePath, String fileName){
        ServletOutputStream out = null;
        try {
            //文件名
            fileName = new StringBuffer(fileName)
                    .append(new SimpleDateFormat("_yyyyMMddHHmmss").format(new Date()))
                    .append(".xlsx")
                    .toString();
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            response.setCharacterEncoding("UTF-8");
            out = response.getOutputStream();

            EasyExcel.write(out, dataList.get(0).getClass())
                    .withTemplate(loadTemplate(templateFilePath))//模板 处理路径读取
                    .needHead(false)//取消导出自带表头
                    .sheet()
                    .doWrite(dataList);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(out);
        }
    }

    public static File loadTemplate(String templatePath){
        FileOutputStream out = null;
        ExcelWriter writer = null;
        File tempFile = null;
        if (StrUtil.isNotBlank(templatePath)){
            try {
                //获取模板文件
                File file = FileUtil.file(templatePath);
                if (!file.exists()){
//                    file = FileUtil.file(file.getAbsolutePath().replace("app.jar!/BOOT-INF/classes!","BOOT-INF/classes"));
                    /**
                     * file.getgetAbsolutePath() 该方法拿到的是"classpath:*"这个绝对路径
                     * 对于linux而言若templatePath为 "classpath:template/exportExpertInfo.xlsx" 则获取到的是 "jar包所在文件夹路径 + jar包名称.jar!/BOOT-INF/classes!/template/exportExpertInfo.xlsx"
                     * 故需要将该路径改为 "jar包所在路径 + BOOT-INF/classes/template/exportExpertInfo.xlsx 这个地址
                     */
                    //获取模板所在jar包中的位置
                    //模板的相对路径 例如 /**/*.jar !/BOOT-INF/classes!/template/templateName.xlsx
                    String absolutePath = file.getAbsolutePath();

                    //从.jar开始分隔开
                    int templateIndexInJar = absolutePath.indexOf(".jar");

                    //获取模板所在jar包中的路径 .jar!/BOOT-INF/classes!/template/templateName.xlsx 再将其替换成 /BOOT-INF/classes/template/templateName.xlsx
                    String templatePathInJar = absolutePath.substring(templateIndexInJar).replace(".jar!/BOOT-INF/classes!", "/BOOT-INF/classes");

                    //获取jar包所在的文件夹路径 /data/marketing-platform
                    String jarDirIndex = absolutePath.substring(0,templateIndexInJar);
                    //获取索引 倒数第一个"/"的索引
                    int jarDirLastIndex = jarDirIndex.lastIndexOf("/");
                    //获取所在文件夹路径 /data
                    String jarDirPath = jarDirIndex.substring(0,jarDirLastIndex);

                    //创建模板文件
                    file = FileUtil.file(jarDirPath + templatePathInJar);
                }
                //创建临时文件
                //1.获取路径
                String tempFilePath = "";
                if (templatePath.endsWith(".xlsx")){
                    tempFilePath = file.getAbsolutePath().replace(".xlsx","_tmp.xlsx");
                }else if(templatePath.endsWith(".xls")){
                    tempFilePath = file.getAbsolutePath().replace(".xls","_tmp.xls");
                }
                //2.创建文件
                tempFile = FileUtil.file(tempFilePath);
                if (!tempFile.exists()){
                    tempFile.createNewFile();
                }
                out = new FileOutputStream(tempFile);
                writer = ExcelUtil.getWriter(file);
                writer.flush(out,true);
            }catch (Exception e){
                throw new RuntimeException(e);
            }finally {
                if (!ObjectUtil.isEmpty(writer)){
                    writer.close();
                }
                if (!ObjectUtil.isEmpty(out)){
                    IoUtil.close(out);
                }
            }
        }
        return tempFile;
    }



    /**
     * 导出数据
     * @param response
     * @param fileName 导出的文件名
     * @param dataList 要导出的源数据
     * @param cls      生成的类型
     * @param <T>
     */
    public static <T> void exportExcelData(HttpServletResponse response, String fileName, List<T> dataList, Class<T> cls) {
        try {
            Field[] fields = cls.getDeclaredFields();
            List<String> includeColumnList = Arrays.stream(fields).filter(column -> null != column.getAnnotation(ExcelProperty.class))
                    .map(Member::getName).collect(Collectors.toList());

            // 这里注意 使用swagger可能会导致各种问题，请直接用浏览器或者用postman
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 头的策略
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            // 设置表头居中对齐
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            // 颜色
            headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 12);
            // 字体
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setWrapped(true);
            // 内容的策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            // 设置内容居中对齐
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
            contentWriteCellStyle.setWrapped(true);
            // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

            EasyExcelFactory.write(response.getOutputStream(), cls).includeColumnFieldNames(includeColumnList).sheet(0)
                    .registerWriteHandler(horizontalCellStyleStrategy).doWrite(dataList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导出表格
     * @param templatePath 模板文件路径
     * @param skipRows 跳过行数
     * @param fileName 文件名称
     * @param data 数据
     * @param headerMap 表头别名
     * @param response 响应对象
     */
    public static void export(String templatePath, Integer skipRows, String fileName, Iterable<?> data, Map<String, String> headerMap, HttpServletResponse response, ExportExcelHandler handler){
        //初始化表格写对象
        ExcelWriter writer = null;
        File templateXlsx = loadTemplate(templatePath);
        //有模板获取模板
        if (!Objects.isNull(templateXlsx)){
            writer = ExcelUtil.getWriter(templateXlsx);
        }else {
            //没有模板创建默认表格
            writer = ExcelUtil.getWriter(true);
        }
        //设置单元格自动换行
        StyleSet style = writer.getStyleSet();
        style.setWrapText();
        writer.setHeaderAlias(headerMap);
        writer.setOnlyAlias(true);

        //跳过标题
        writer.passRows(skipRows);
        //不输出表头
        writer.write(data,false);
        //回调做一些附加处理
        if (ObjectUtil.isNotEmpty(handler)){
            handler.handle(writer);
        }

        //导出
        ServletOutputStream out = null;
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
            response.setCharacterEncoding("UTF-8");
            out = response.getOutputStream();
            writer.flush(out, true);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            writer.close();
            IoUtil.close(out);
            FileUtil.del(templateXlsx);
        }
    }




}
